home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume18 / rh < prev    next >
Encoding:
Internet Message Format  |  1989-03-23  |  44.0 KB

  1. Subject:  v18i058:  Find files using C-style expressions
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Kenneth Stauffer <stauffer@cpsc.UCalgary.CA>
  7. Posting-number: Volume 18, Issue 58
  8. Archive-name: rh
  9.  
  10. Rh, was written by Ken Stauffer to make the job of finding files easier by
  11. allowing the user to enter real C expressions. This notation is much
  12. easier to master than the notation used by the Unix find(1) command,
  13. partly because most Unix users already know C and party because the syntax
  14. is more consistant. In addition to being easier to use than find(1), its
  15. expressions can be used to select a more diverse subset of files.
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of shell archive."
  24. # Contents:  README Makefile rh.h rh.c rhcmds.c rhdir.c rhparse.c
  25. #   rh.man sample
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'README' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'README'\"
  29. else
  30. echo shar: Extracting \"'README'\" \(3050 characters\)
  31. sed "s/^X//" >'README' <<'END_OF_FILE'
  32. X                            March 6, 1989
  33. X
  34. XINTRODUCTION:
  35. XRh, was written by Ken Stauffer (c)1989, to make the
  36. Xjob of finding files easier by allowing the
  37. Xuser to enter real C expressions. This notation is
  38. Xmuch easier to master than the notation used by the
  39. XUnix find(1) command, partly because most Unix users
  40. Xalready know C and party because the syntax is more
  41. Xconsistant. In addition to being easier to use
  42. Xthan find(1), its expressions can be used to select
  43. Xa more diverse subset of files.
  44. X
  45. XPORTABILITY:
  46. XIn the makefile the user must specify what flavour of unix
  47. Xthey are making rh for. For the most part rh is portable
  48. Xto all unix systems, except for the portion of code
  49. Xthat does the directory reading. The code that does this
  50. Xhas been isolated in the file 'rhdir.c'. There are two basic
  51. Xmechanisms I have seen for directory reading:
  52. X
  53. X    XENIX / SYSV:
  54. X    ------------
  55. X        This method simply opens the directory as a file
  56. X    and does fread()'s to grab the directory entries. This is
  57. X    the simplest and most obvious way. However on BSD systems
  58. X    a library routine is placed between the programmer and
  59. X    the system call interface for portablility reasons.
  60. X
  61. X    BSD:
  62. X    ---
  63. X        Berkley adds the readdir() routine. Which has
  64. X    its own data type, DIR which is used for the
  65. X    reading of directories. However the structure to which these
  66. X    entries are placed is still 'struct direct'. This again differs
  67. X    from the SUN implementation.
  68. X
  69. X    SUN:
  70. X    ---
  71. X        Sun OS, is similar to BSD except that an include
  72. X    file is different, and also it uses a 'struct dirent'
  73. X    instead of 'struct direct'.
  74. X
  75. X    All of these differences have been taken into account in
  76. X    the file 'rhdir.c', and hopefully will work on your system.
  77. X    So far 'rh' works on:
  78. X        SCO XENIX, VAX (BSD 4.3) and SUN 4's (and SUN 3's).
  79. X
  80. X    If your system is different from the ones above, then
  81. X    the modifications should be made to 'rhdir.c' ONLY.
  82. X
  83. XCOMPILING:
  84. XTo make rh work on your system, the file Makefile must be
  85. Xedited to match your system. There is a single '-D' option
  86. Xthat must be changed in the Makefile. Define ONE of the
  87. Xfollowing in the definition of CFLAGS:
  88. X
  89. X    -DBSD        - This would be used for
  90. X              most BSD systems. (VAX's)
  91. X    -DSUN        - This would be used for
  92. X              SUN computers. (SUN 4 / SUN 3)
  93. X    -DXENIX        - Xenix systems. (Tandy 6000)
  94. X    -DSYSV        - System V systems.
  95. X
  96. XIn addition to the C source there is also a file called
  97. Xrh.man. This is a nroff file and can be created by a command like:
  98. X        nroff -man rh.man > rh.cat
  99. XThe resultant file (rh.cat) is sutable for general viewing.
  100. X
  101. XFinally there is a file called sample. This file contains some
  102. Xsample rh expressions. To use them the user can type:
  103. X
  104. X    % rh -l -f sample -mex1
  105. X
  106. XThis would do a search of the current working directory, and
  107. Xuse the expression 'ex1' from the file 'sample'.
  108. X
  109. XOnce rh is made, you can do what you want with it. A good test to
  110. Xsee if it is working is to do a:
  111. X
  112. X    % rh -la -e 1 /
  113. X
  114. XThis will find all files that makes the constant exression '1' true.
  115. XSo unless your not root, all files on the system will be printed.
  116. X
  117. XKen Stauffer.
  118. X
  119. XI can be reached via email at:
  120. X        root@sixk
  121. END_OF_FILE
  122. if test 3050 -ne `wc -c <'README'`; then
  123.     echo shar: \"'README'\" unpacked with wrong size!
  124. fi
  125. # end of 'README'
  126. fi
  127. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  128.   echo shar: Will not clobber existing file \"'Makefile'\"
  129. else
  130. echo shar: Extracting \"'Makefile'\" \(530 characters\)
  131. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  132. X# rh:
  133. X# (c) 1989 Ken Stauffer
  134. X#
  135. X# Place one of the following -D's onto the end of
  136. X# the definition of CFLAGS.
  137. X#
  138. X# -DXENIX
  139. X#    - xenix like OS
  140. X#
  141. X# -DSYSV
  142. X#    - System V/III like OS
  143. X#
  144. X# -DBSD
  145. X#    - BSD like OS
  146. X#
  147. X# -DSUN
  148. X#    - SUN OS
  149. X#
  150. X
  151. XCFLAGS= -DXENIX -O -n
  152. X
  153. Xrh: rhcmds.o rh.o rhparse.o rhdir.o
  154. X    cc $(CFLAGS) -o rh rh.o rhcmds.o rhparse.o rhdir.o
  155. X
  156. Xrhdir.o: rhdir.c rh.h
  157. X    cc $(CFLAGS) -c rhdir.c
  158. X
  159. Xrh.o: rh.c rh.h
  160. X    cc $(CFLAGS) -c rh.c
  161. X
  162. Xrhcmds.o: rhcmds.c rh.h
  163. X    cc $(CFLAGS) -c rhcmds.c
  164. X
  165. Xrhparse.o: rhparse.c rh.h
  166. X    cc $(CFLAGS) -c rhparse.c
  167. X
  168. END_OF_FILE
  169. if test 530 -ne `wc -c <'Makefile'`; then
  170.     echo shar: \"'Makefile'\" unpacked with wrong size!
  171. fi
  172. # end of 'Makefile'
  173. fi
  174. if test -f 'rh.h' -a "${1}" != "-c" ; then 
  175.   echo shar: Will not clobber existing file \"'rh.h'\"
  176. else
  177. echo shar: Extracting \"'rh.h'\" \(4290 characters\)
  178. sed "s/^X//" >'rh.h' <<'END_OF_FILE'
  179. X
  180. X/* ----------------------------------------------------------------------
  181. X * FILE: rh.h
  182. X * (c) 1989 Ken Stauffer
  183. X * This header contains the #define's for the tokens.
  184. X * It also contains the initialized arrays. By having 
  185. X * rh.c define a symbol MAIN, the space is allocated for these globals
  186. X * only once.
  187. X *
  188. X * ---------------------------------------------------------------------- */
  189. X
  190. X#include <stdio.h>
  191. X
  192. X#define START        256
  193. X#define OR        256    /* || */
  194. X#define AND        257    /* && */
  195. X#define LE        258    /* <= */
  196. X#define LT        259    /* < */
  197. X#define GE        260    /* >= */
  198. X#define GT        261    /* > */
  199. X#define NE        262    /* != */
  200. X#define EQ        263    /* == */
  201. X#define BOR        264    /* | */
  202. X#define BAND        265    /* & */
  203. X#define BXOR        266    /* ^ */
  204. X#define NOT        267    /* ! */
  205. X#define PLUS        268    /* + */
  206. X#define MUL        269    /* * */
  207. X#define MINUS        270    /* - */
  208. X#define DIV        271    /* / */
  209. X#define MOD        272    /* % */
  210. X#define BNOT        273    /* ~ */
  211. X#define UNIMINUS    274    /* - */
  212. X#define SHIFTL        275    /* << */
  213. X#define SHIFTR        276    /* >> */
  214. X#define QM        277    /* ? */
  215. X#define COLON        278    /* : */
  216. X#define NOP        279    /* */
  217. X#define NUMBER        280    /* eg. 1234,NOW,IFDIR */
  218. X#define STAR        281    /* eg. "*.BAK" */
  219. X#define FIELD        282    /* mode, uid */
  220. X#define MACRONAME    283
  221. X#define UNKNOWN        284
  222. X
  223. X#define NOW_INDEX    1    /* where to place the current time */
  224. X#define MACRO_INDEX    0    /* where the macro name goes */
  225. X#define LENGTH        100    /* size of stack program */
  226. X#define MEM        20    /* size of stack */
  227. X#define IDLENGTH    20
  228. X#define STARLEN        1000    /* total chars available for strings */
  229. X
  230. X#if BSD || SUN
  231. X#define DEPTH        getdtablesize()
  232. X#endif
  233. X
  234. X#if XENIX || SYSV
  235. X/* This value was arbitrarily chosen */
  236. X#define DEPTH        24
  237. X#endif
  238. X
  239. Xstruct instr {
  240. X    int        i_type;
  241. X    long        i_value;
  242. X};
  243. X
  244. X#ifdef MAIN
  245. X
  246. Xextern    c_or(),      c_and(),      c_le(),      c_lt(),      c_ge(),
  247. X    c_gt(),      c_ne(),       c_eq(),      c_bor(),     c_band(),
  248. X    c_bxor(),    c_not(),      c_plus(),    c_mul(),     c_minus(),
  249. X    c_div(),     c_mod(),      c_number(),  c_atime(),   c_ctime(),
  250. X    c_dev(),     c_gid(),      c_ino(),     c_mode(),    c_mtime(),
  251. X    c_nlink(),   c_rdev(),     c_size(),    c_uid(),     c_star(),
  252. X    c_bnot(),    c_uniminus(), c_lshift(),  c_rshift(),  c_qm(),
  253. X    c_colon(),   c_nop();
  254. X
  255. X#if SUN || BSD
  256. Xchar *identifiers[]={ "", "NOW" , "IFBLK", "IFCHR", "IFDIR", "IFLNK", "IFMT",
  257. X              "IFREG", "IFSOCK", "ISGID", "ISUID", "ISVTX",
  258. X              "atime",  "ctime", "dev",   "gid",  "ino",
  259. X              "mode",  "mtime",  "nlink", "rdev",  "size", "uid",
  260. X              NULL };
  261. X
  262. Xlong constants[]={ 0,0,
  263. X    S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK,
  264. X    S_ISGID, S_ISUID, S_ISVTX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  265. X#endif
  266. X
  267. X#if XENIX || SYSV
  268. Xchar *identifiers[]={ "", "NOW", "IFBLK", "IFCHR", "IFDIR", "IFMT",
  269. X              "IFREG", "IFIFO", "ISGID", "ISUID", "ISVTX",
  270. X               "atime",  "ctime", "dev",   "gid",  "ino",
  271. X              "mode",  "mtime",  "nlink", "rdev",  "size", "uid",
  272. X              NULL };
  273. X
  274. Xlong constants[]={ 0,0,
  275. X    S_IFBLK, S_IFCHR, S_IFDIR, S_IFMT, S_IFREG, S_IFIFO,
  276. X    S_ISGID, S_ISUID, S_ISVTX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  277. X#endif
  278. X
  279. Xint (*commands[])()= {
  280. X    c_or,      c_and,      c_le,      c_lt,      c_ge,
  281. X    c_gt,      c_ne,       c_eq,      c_bor,     c_band,
  282. X    c_bxor,    c_not,      c_plus,    c_mul,     c_minus,
  283. X    c_div,     c_mod,      c_bnot,    c_uniminus,c_lshift,
  284. X    c_rshift,  c_qm,       c_colon,   c_nop,     c_number,
  285. X    c_star,    c_atime,    c_ctime,   c_dev,     c_gid,
  286. X    c_ino,     c_mode,     c_mtime,   c_nlink,   c_rdev,
  287. X    c_size,    c_uid };
  288. X
  289. X    long        tokenval;
  290. X    long        token;
  291. X
  292. X    struct instr    StackProgram[ LENGTH ];
  293. X    int        PC;
  294. X
  295. X    long        Stack[ MEM ];
  296. X    int        SP;
  297. X
  298. X    struct stat    *globuf;
  299. X    char        *fname;
  300. X    int        dashf;
  301. X    int        dashl;
  302. X    int        dashe;
  303. X    int        dashr;
  304. X    int        dashh;
  305. X    int        dashm;
  306. X    int        dasha;
  307. X    char        *expstr;
  308. X    FILE        *expfile;
  309. X    
  310. X    char        Starbuf[ STARLEN ];
  311. X    int        starfree=0;
  312. X
  313. X#else
  314. X    extern long        constants[];
  315. X    extern char        *identifiers[];
  316. X    extern int        (*commands[])();
  317. X
  318. X    extern long        tokenval;
  319. X    extern long        token;
  320. X    extern struct instr    StackProgram[];
  321. X    extern int        PC;
  322. X    extern long        Stack[];
  323. X    extern int        SP;
  324. X    extern struct stat    *globuf;
  325. X    extern char        *fname;
  326. X    extern char        Starbuf[];
  327. X    extern int        starfree;
  328. X    extern int        dashf;
  329. X    extern int        dashl;
  330. X    extern int        dashe;
  331. X    extern int        dashr;
  332. X    extern int        dashh;
  333. X    extern int        dashm;
  334. X    extern int        dasha;
  335. X    extern char        *expstr;
  336. X    extern FILE        *expfile;
  337. X#endif
  338. END_OF_FILE
  339. if test 4290 -ne `wc -c <'rh.h'`; then
  340.     echo shar: \"'rh.h'\" unpacked with wrong size!
  341. fi
  342. # end of 'rh.h'
  343. fi
  344. if test -f 'rh.c' -a "${1}" != "-c" ; then 
  345.   echo shar: Will not clobber existing file \"'rh.c'\"
  346. else
  347. echo shar: Extracting \"'rh.c'\" \(5063 characters\)
  348. sed "s/^X//" >'rh.c' <<'END_OF_FILE'
  349. X
  350. X/* ----------------------------------------------------------------------
  351. X * FILE: rh.c
  352. X * (c) 1989 Ken Stauffer
  353. X * 
  354. X * printhelp(), execute(), examine(), main()
  355. X *
  356. X *
  357. X * ---------------------------------------------------------------------- */
  358. X
  359. X#include <sys/types.h>
  360. X#include <sys/stat.h>
  361. X#define MAIN
  362. X#include "rh.h"
  363. X
  364. Xstatic char usage[]={
  365. X"Usage: %s [-ahlr] [ [-e expr] | [-f filename [-mname]] ] file ...\n"
  366. X};
  367. X
  368. X
  369. X/* ----------------------------------------------------------------------
  370. X * printhelp:
  371. X *    Print out the help screen. The string 's' is argv[0].
  372. X *    Called when the -h option is used.
  373. X *
  374. X */
  375. X
  376. Xprinthelp(s)
  377. Xchar *s;
  378. X{
  379. X   int i;
  380. X
  381. X    printf(usage,s);
  382. X    printf("options:\n");
  383. X    printf("\t-h       show this message\n");
  384. X    printf("\t-l       long filename output\n");
  385. X    printf("\t-r       makes %s non-recursive\n",s);
  386. X    printf("\t-a       adds to the long output to make it longer\n");
  387. X    printf("\t-mname   use the named macro 'name' from 'file'\n");
  388. X    printf("\t-e       get expression from the command line\n");
  389. X    printf("\t-f       get expression from file\n\n");
  390. X    printf("VALID EXPRESSIONS CONSIST OF:\n");
  391. X
  392. X    printf("\tCONSTANTS/variables: see stat(2)\n");
  393. X    for(i=0; identifiers[i]; i++ )
  394. X        printf("%s%12s%s", (!(i%5==0)) ? "\t" : "" , 
  395. X            identifiers[i],
  396. X            (i%5==4 || !identifiers[i+1]) ? "\n" : " ");
  397. X
  398. X    printf("\tC OPERATORS (precedence same as C):\n");
  399. X    printf("\t! ~ - * / %% + < <= > >= == != & ^ | << >> && || ?:\n");
  400. X    printf("\tSPECIAL OPERATORS:\n");
  401. X    printf("\t$username , \"*.c\" , [yyyy/mm/dd]\n\n");
  402. X
  403. X}
  404. X
  405. X/* ----------------------------------------------------------------------
  406. X * execute:
  407. X *    Execute the program contained in the StackProgram[]
  408. X *    array.
  409. X *    Indexes the commands[] array to obtain the correct
  410. X *    function/operator. Programs are NULL terminated.
  411. X *    Returns the result of the expression.
  412. X *
  413. X */
  414. X
  415. Xexecute()
  416. X{
  417. X    register long etype,eval;
  418. X    SP=0;
  419. X    for(PC=0; (etype=StackProgram[PC].i_type) ; PC++) {
  420. X        eval=StackProgram[PC].i_value;
  421. X
  422. X    (*commands[ (etype!=FIELD) ? etype-START : etype-START+eval ] ) (eval);
  423. X
  424. X    }
  425. X    return( Stack[0] );
  426. X}
  427. X
  428. X/* ----------------------------------------------------------------------
  429. X * examine:
  430. X *    This function is called for every file that 'rh' examines.
  431. X *    examine() first calls execute to see if the
  432. X *    expression is true, it then prints the file if the expression
  433. X *    evaluated to true (non-zero).
  434. X *
  435. X */
  436. X
  437. Xexamine(s,buf)
  438. Xchar *s;
  439. Xstruct stat *buf;
  440. X{
  441. X    fname=s;
  442. X    globuf=buf;
  443. X
  444. X    if( execute() )
  445. X        (dashl) ? printentry(globuf,fname) : printf("%s\n",fname);
  446. X}
  447. X
  448. X/* ----------------------------------------------------------------------
  449. X * main:
  450. X *    parse arguments.
  451. X *    two for loops are used to parse the argument list,
  452. X *    the first for loop process the arguments. The second
  453. X *    for loop process the characters within the current argument.
  454. X *    -l, -r, -h options can occur as often as desired.
  455. X *    -f and -e and -m can only occur once and MUST have an argument.
  456. X *
  457. X *    parse expression.
  458. X *    the expression is parsed and if all is ok, then the
  459. X *    recursive hunt is started.
  460. X *
  461. X */
  462. X
  463. Xmain(argc,argv)
  464. Xint argc;
  465. Xchar *argv[];
  466. X{
  467. X    int i,r,skip;
  468. X    char *j;
  469. X
  470. X    /* defaults */
  471. X    dashe = 0;        /* -e option */
  472. X    dashl = 0;        /* -l */
  473. X    dashf = 0;        /* -f */
  474. X    dashr = 1;        /* -r */
  475. X    dashh = 0;        /* -h */
  476. X    dashm = 0;        /* -m */
  477. X    dasha = 0;        /* -a */
  478. X    
  479. X   for(i=1; i<argc; i++ ) {
  480. X    if( *argv[i] != '-' ) break;
  481. X    skip = 0;
  482. X    for(j=argv[i]+1; *j; j++ ) {
  483. X       switch( *j ) {
  484. X       case 'l': dashl = 1; break;
  485. X       case 'r': dashr = 0; break;
  486. X       case 'h': dashh = 1; break;
  487. X       case 'a': dashl = dasha = 1; break;
  488. X       case 'm':
  489. X        if( dashm ) {
  490. X            fprintf(stderr,"%s: too many -m options\n", argv[0]);
  491. X            exit(-1);
  492. X        }
  493. X        dashm = 1;
  494. X        identifiers[ MACRO_INDEX ] = j+1;
  495. X        while(*j) j++; j--;
  496. X        break;
  497. X       case 'e':
  498. X        if( dashe ) {
  499. X            fprintf(stderr, "%s: too many -e options\n",argv[0]);
  500. X            exit(-1);
  501. X        }
  502. X        dashe = i+1;
  503. X        skip = 1;
  504. X        break;
  505. X       case 'f':
  506. X        if( dashf ) {
  507. X            fprintf(stderr, "%s: too many -f options\n",argv[0]);
  508. X            exit(-1);
  509. X        } 
  510. X        dashf = i+1;
  511. X        skip = 1;
  512. X        break;
  513. X       default:
  514. X        fprintf(stderr,"%s: illegal option -%c, use -h for help\n",
  515. X        argv[0],*j);
  516. X        fprintf(stderr,usage, argv[0]);
  517. X        exit(-1);
  518. X       }
  519. X       if( dashf && dashe ) {
  520. X        fprintf(stderr, "%s: cannot have both -e and -f\n",argv[0]);
  521. X        exit(-1);
  522. X       }
  523. X    }
  524. X    if( skip ) i++;
  525. X   }
  526. X
  527. X    if( dashh ) printhelp(argv[0]);
  528. X
  529. X    if( dashm && !dashf ) {
  530. X        fprintf(stderr,"%s: -m option needs the -f option\n",argv[0]);
  531. X        exit(-1);
  532. X    }
  533. X    if( dashf >= argc ) {
  534. X        fprintf(stderr,"%s: -f missing an argument\n",argv[0]);
  535. X        exit(-1);
  536. X    }
  537. X    if( dashe >= argc ) {
  538. X        fprintf(stderr,"%s: -e missing an argument\n",argv[0]);
  539. X        exit(-1);
  540. X    }
  541. X    
  542. X    if( dashe ) { expstr = argv[dashe]; }
  543. X    else if( dashf ) {
  544. X        expstr = argv[dashf];
  545. X        if( (expfile = fopen(expstr,"r")) == NULL ) {
  546. X            fprintf(stdout,"%s: cannot open %s\n",
  547. X                argv[0],expstr);
  548. X            exit(-1);
  549. X        }
  550. X    } else expfile = stdin;
  551. X    
  552. X    expression();
  553. X
  554. X    if( i >= argc ) {
  555. X        r=ftw(".",examine,(dashr)? DEPTH :1);
  556. X        if(r == -1) perror(".");
  557. X    } else
  558. X        for(; i<argc; i++) {
  559. X            r=ftw( argv[i],examine,(dashr)? DEPTH :1);
  560. X            if( r == -1 ) perror(argv[i]);
  561. X        }
  562. X}
  563. END_OF_FILE
  564. if test 5063 -ne `wc -c <'rh.c'`; then
  565.     echo shar: \"'rh.c'\" unpacked with wrong size!
  566. fi
  567. # end of 'rh.c'
  568. fi
  569. if test -f 'rhcmds.c' -a "${1}" != "-c" ; then 
  570.   echo shar: Will not clobber existing file \"'rhcmds.c'\"
  571. else
  572. echo shar: Extracting \"'rhcmds.c'\" \(3879 characters\)
  573. sed "s/^X//" >'rhcmds.c' <<'END_OF_FILE'
  574. X
  575. X/* ----------------------------------------------------------------------
  576. X * FILE: rhcmds.c
  577. X * (c) 1989 Ken Stauffer
  578. X * This file contains the functions that do the evaluation of
  579. X * the stack program.
  580. X * These functions are simple, and behave like RPN operators, that is
  581. X * they use the last two values on that stack, apply an operator
  582. X * and push the result. Similarly for unary ops.
  583. X *
  584. X * ---------------------------------------------------------------------- */
  585. X
  586. X#include "rh.h"
  587. X#include <sys/types.h>
  588. X#include <sys/stat.h>
  589. X
  590. Xc_or(i)   long i;   { Stack[SP-2]=Stack[SP-2] || Stack[SP-1]; SP--; }
  591. Xc_and(i)  long i;   { Stack[SP-2]=Stack[SP-2] && Stack[SP-1]; SP--; }
  592. Xc_le(i)   long i;   { Stack[SP-2]=Stack[SP-2] <= Stack[SP-1]; SP--; }
  593. Xc_lt(i)   long i;   { Stack[SP-2]=Stack[SP-2] < Stack[SP-1]; SP--;  }
  594. Xc_ge(i)   long i;   { Stack[SP-2]=Stack[SP-2] >= Stack[SP-1]; SP--; }
  595. Xc_gt(i)   long i;   { Stack[SP-2]=Stack[SP-2] > Stack[SP-1]; SP--;  }
  596. Xc_ne(i)   long i;   { Stack[SP-2]=Stack[SP-2] != Stack[SP-1]; SP--; }
  597. Xc_eq(i)   long i;   { Stack[SP-2]=Stack[SP-2] == Stack[SP-1]; SP--; }
  598. Xc_bor(i)  long i;   { Stack[SP-2]=Stack[SP-2] | Stack[SP-1]; SP--;  }
  599. Xc_band(i) long i;   { Stack[SP-2]=Stack[SP-2] & Stack[SP-1]; SP--;  }
  600. Xc_bxor(i) long i;   { Stack[SP-2]=Stack[SP-2] ^ Stack[SP-1]; SP--;  }
  601. Xc_plus(i) long i;   { Stack[SP-2]=Stack[SP-2] + Stack[SP-1];SP--;   }
  602. Xc_mul(i)  long i;   { Stack[SP-2]=Stack[SP-2] * Stack[SP-1]; SP--;  }
  603. Xc_minus(i)long i;   { Stack[SP-2]=Stack[SP-2] - Stack[SP-1]; SP--;  }
  604. Xc_div(i)  long i;   { Stack[SP-2]=Stack[SP-2] / Stack[SP-1]; SP--;  }
  605. Xc_mod(i)  long i;   { Stack[SP-2]=Stack[SP-2] % Stack[SP-1]; SP--;  }
  606. Xc_lshift(i) long i; { Stack[SP-2]=Stack[SP-2] << Stack[SP-1]; SP--;  }
  607. Xc_rshift(i) long i; { Stack[SP-2]=Stack[SP-2] >> Stack[SP-1]; SP--;  }
  608. X
  609. X/* unary instructions */
  610. X
  611. Xc_not(i)      long i; { Stack[SP-1]= ! Stack[SP-1]; }
  612. Xc_bnot(i)     long i; { Stack[SP-1]= ~ Stack[SP-1]; }
  613. Xc_uniminus(i) long i; { Stack[SP-1]= - Stack[SP-1]; }
  614. X
  615. X/* trinary operator ?: */
  616. X
  617. Xc_qm(i)    long i; { PC = (Stack[SP-1]) ?  PC : i; SP--; }
  618. Xc_colon(i) long i; { PC = i; }
  619. Xc_nop(i)   long i; { }
  620. X
  621. X/* operand functions */
  622. X
  623. Xc_number(i) long i; { Stack[SP++] = i;                }
  624. Xc_atime(i)  long i; { Stack[SP++] = globuf->st_atime; }
  625. Xc_ctime(i)  long i; { Stack[SP++] = globuf->st_ctime; }
  626. Xc_dev(i)    long i; { Stack[SP++] = globuf->st_dev;   }
  627. Xc_gid(i)    long i; { Stack[SP++] = globuf->st_gid;   }
  628. Xc_ino(i)    long i; { Stack[SP++] = globuf->st_ino;   }
  629. Xc_mode(i)   long i; { Stack[SP++] = globuf->st_mode;  }
  630. Xc_mtime(i)  long i; { Stack[SP++] = globuf->st_mtime; }
  631. Xc_nlink(i)  long i; { Stack[SP++] = globuf->st_nlink; }
  632. Xc_rdev(i)   long i; { Stack[SP++] = globuf->st_rdev;  }
  633. Xc_size(i)   long i; { Stack[SP++] = globuf->st_size;  }
  634. Xc_uid(i)    long i; { Stack[SP++] = globuf->st_uid;   }
  635. X
  636. X
  637. X/* ----------------------------------------------------------------------
  638. X * star:
  639. X *    This implements the trivial regular expression stuff.
  640. X *    Since people may want to upgrade this, I will explain the
  641. X *    parameter. 'i' is an index into the array Startbuf[]. The
  642. X *    string contained there is the actual '\0' terminated
  643. X *    string that occured in the expression (eg "*.BAK" ), minus
  644. X *    the "'s.
  645. X *    The reasons for the simplistic regular expressions is
  646. X *    because it was easy, because lots of unix systems do
  647. X *    regexp() in lots of ways and this method is fairly fast.
  648. X *
  649. X */
  650. X
  651. Xc_star(i)
  652. Xlong i;
  653. X{
  654. X
  655. X    register int ri,ii;
  656. X    
  657. X    if( Starbuf[i]=='*') {
  658. X        ii=strlen(fname)-1;
  659. X        ri=strlen(Starbuf+i)-1+i;
  660. X        while( fname[ii]==Starbuf[ri] && ri>i ) {
  661. X            ri--; ii--;
  662. X        }
  663. X        Stack[SP++] = (ri==i);
  664. X    }
  665. X    else {
  666. X        int x=0;
  667. X        ii=0;
  668. X        while( fname[x] ) {
  669. X            if(fname[x]=='/') ii=x;
  670. X            x++;
  671. X        }
  672. X        ii++;
  673. X        ri=i;
  674. X        while( fname[ii]==Starbuf[ri] && Starbuf[ri]!='*' 
  675. X            && fname[ii] && Starbuf[ri]) {
  676. X            ri++; ii++;
  677. X        }
  678. X        Stack[SP++]=!(fname[ii]+Starbuf[ri]) || Starbuf[ri]=='*';
  679. X    }
  680. X}
  681. X
  682. END_OF_FILE
  683. if test 3879 -ne `wc -c <'rhcmds.c'`; then
  684.     echo shar: \"'rhcmds.c'\" unpacked with wrong size!
  685. fi
  686. # end of 'rhcmds.c'
  687. fi
  688. if test -f 'rhdir.c' -a "${1}" != "-c" ; then 
  689.   echo shar: Will not clobber existing file \"'rhdir.c'\"
  690. else
  691. echo shar: Extracting \"'rhdir.c'\" \(5549 characters\)
  692. sed "s/^X//" >'rhdir.c' <<'END_OF_FILE'
  693. X
  694. X/* ----------------------------------------------------------------------
  695. X * FILE: rhdir.c
  696. X * (c) 1989 Ken Stauffer
  697. X * This file contains the "non portable" stuff dealing with
  698. X * directories.
  699. X * printentry(), ftw(), ftw1()
  700. X *
  701. X *
  702. X * ---------------------------------------------------------------------- */
  703. X
  704. X#include "rh.h"
  705. X#include <sys/types.h>
  706. X#include <sys/stat.h>
  707. X
  708. X#define user_index(b)    ((000777 & b) >> 6) + (b & S_ISUID ? 8 : 0) 
  709. X#define group_index(b)    ((000077 & b) >> 3) + (b & S_ISGID ? 8 : 0)
  710. X#define all_index(b)    ((000007 & b) + ((b & S_ISVTX) ? 8 : 0))
  711. X#define ftype_index(b)    (b >> 13)
  712. X
  713. X#define isdirect(b)    ((b&S_IFMT)==S_IFDIR)
  714. X
  715. X#if SUN
  716. X
  717. X#include <dirent.h>
  718. X#define MAXPATHLEN    255
  719. X#define islink(b)    ((b & S_IFLNK) == S_IFLNK)
  720. X#define isproper(m)    ( isdirect(m) && !(((m)&S_IFLNK)==S_IFLNK) )
  721. X
  722. X#endif
  723. X
  724. X#if BSD
  725. X
  726. X#include <sys/dir.h>
  727. X#define MAXPATHLEN    255
  728. X#define islink(b)    ((b & S_IFLNK) == S_IFLNK)
  729. X#define isproper(m)    ( isdirect(m) && !(((m)&S_IFLNK)==S_IFLNK) )
  730. X
  731. X#endif
  732. X
  733. X#if XENIX || SYSV
  734. X
  735. X#include <sys/dir.h>
  736. X#define MAXPATHLEN    255
  737. X#define islink(b)    (0)
  738. X#define isproper(m)    isdirect(m)
  739. X#define lstat        stat
  740. X
  741. X#endif
  742. X
  743. X
  744. Xstatic int (*func)();
  745. Xstatic char filename[ MAXPATHLEN ];
  746. X
  747. X/* ----------------------------------------------------------------------
  748. X * printentry:
  749. X *    Display filename,permissions and size in a '/bin/ls' like
  750. X *    format. Examines the dasha variable to see if more
  751. X *    info should be printed.
  752. X * uses the macros:
  753. X *    user_index(b)
  754. X *    group_index(b)
  755. X *    all_index(b)
  756. X *    ftype_index(b)
  757. X *
  758. X */
  759. X
  760. Xprintentry(buf,name)
  761. Xstruct stat *buf;
  762. Xchar *name;
  763. X{
  764. X    char *t,*ctime();
  765. X
  766. X    static char *ftype[]={ "p", "c" , 
  767. X                   "d" , "b" ,  
  768. X                   "-" , "l" , 
  769. X                   "s" , "t" };
  770. X    static char *perm[]={ "---", "--x", "-w-", "-wx" ,
  771. X                  "r--", "r-x", "rw-", "rwx" ,
  772. X                  "--S", "--s", "-wS", "-ws" ,
  773. X                  "r-S", "r-s", "rwS", "rws" };
  774. X
  775. X    static char *perm2[]={ "---", "--x", "-w-", "-wx" ,
  776. X                  "r--", "r-x", "rw-", "rwx" ,
  777. X                  "--T", "--t", "-wT", "-wt" ,
  778. X                  "r-T", "r-t", "rwT", "rwt" };
  779. X    if( dasha ) {
  780. X        t = ctime(&buf->st_mtime);
  781. X        t[24] = '\0';
  782. X        printf("%s%s%s%s %4d %4d %6d %s %-s\n",
  783. X            ftype[ ftype_index(buf->st_mode) ],
  784. X            perm[ user_index(buf->st_mode) ],
  785. X            perm[ group_index(buf->st_mode) ],
  786. X            perm2[ all_index(buf->st_mode) ],
  787. X            buf->st_uid,
  788. X            buf->st_gid,
  789. X            buf->st_size,
  790. X            t+4,
  791. X            name );
  792. X    } else {
  793. X        printf("%s%s%s%s %9d %-s\n",
  794. X            ftype[ ftype_index(buf->st_mode) ],
  795. X            perm[ user_index(buf->st_mode) ],
  796. X            perm[ group_index(buf->st_mode) ],
  797. X            perm2[ all_index(buf->st_mode) ],
  798. X            buf->st_size,
  799. X            name );
  800. X    }
  801. X}
  802. X
  803. X/* ----------------------------------------------------------------------
  804. X * ftw:
  805. X *    Entry point to do the search, ftw is a front end
  806. X *    to the recursive fwt1.
  807. X *    ftw() places some of the arguments to global variables
  808. X *    so that they arguments would not have to be passed around to
  809. X *    ftw1().
  810. X *
  811. X */
  812. X
  813. Xftw(f,fn,depth)
  814. Xchar *f;
  815. Xint (*fn)();
  816. Xint depth;
  817. X{
  818. X    char *p;
  819. X    struct stat statbuf;
  820. X    int i;
  821. X
  822. X    strcpy(filename,f);
  823. X    if( filename[ strlen(filename)-1 ] != '/' ) {
  824. X        filename[ strlen(f) ] = '/';
  825. X        filename[ strlen(f)+1 ] = '\0';
  826. X    }
  827. X    func=fn;
  828. X    
  829. X    if( lstat(f,&statbuf) < 0 ) return(-1);
  830. X
  831. X    (*func)(f,&statbuf);
  832. X
  833. X    if( isproper( statbuf.st_mode ) ) fwt1(depth);
  834. X
  835. X    return(0);
  836. X}
  837. X
  838. X/* ----------------------------------------------------------------------
  839. X * fwt1:
  840. X *    2 versions of this routine currently live here:
  841. X *    XENIX/SYSV, and SUN/BSD. They both differ in
  842. X *    the manner in which they access directories.
  843. X *    Any chnages needed to work on another system
  844. X *    should only have to made for this routine.
  845. X *
  846. X *    Below is the SUN/BSD version of fwt1()
  847. X *    --------------------------------------
  848. X *
  849. X */
  850. X
  851. X#if SUN || BSD
  852. X
  853. Xstatic fwt1(depth)
  854. Xint depth;
  855. X{
  856. X
  857. X#if SUN
  858. X    DIR *dirp;
  859. X    struct dirent *dp;
  860. X#else
  861. X    DIR *dirp;
  862. X    struct direct *dp;
  863. X#endif
  864. X    char *basep;
  865. X    struct stat statbuf;
  866. X
  867. X    if( !depth ) return;
  868. X    basep=filename+strlen(filename);
  869. X
  870. X    dirp=opendir(filename);
  871. X    if( dirp == NULL ) return;
  872. X    for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  873. X        if( dp->d_name[0]=='.' && dp->d_name[1]=='\0' ) continue;
  874. X        if( dp->d_name[0]=='.' && dp->d_name[1]=='.' &&
  875. X            dp->d_name[2]=='\0' ) continue;
  876. X        strcpy(basep,dp->d_name);
  877. X        if( lstat(filename,&statbuf) < 0 ) continue;
  878. X        (*func)(filename,&statbuf);
  879. X        if( isproper( statbuf.st_mode ) ) {
  880. X            basep[ strlen(dp->d_name) ] = '/';
  881. X            basep[ strlen(dp->d_name)+1 ] = '\0';
  882. X            fwt1(depth-1);
  883. X        }
  884. X    }
  885. X    closedir(dirp);
  886. X    *basep = '\0';
  887. X}
  888. X#endif
  889. X
  890. X/* ----------------------------------------------------------------------
  891. X * ftw1:
  892. X *    This function does the samething as ftw1() above, but is
  893. X *    meant for XENIX/SYSV type systems that do directory reading
  894. X *    "by hand"
  895. X *
  896. X *    Below is the XENIX/SYSV version of fwt1()
  897. X *    --------------------------------------
  898. X */
  899. X
  900. X#if XENIX || SYSV
  901. X
  902. Xstatic fwt1(depth)
  903. Xint depth;
  904. X{
  905. X    char *basep;
  906. X    FILE *dirp;
  907. X    struct direct dp;
  908. X    struct stat statbuf;
  909. X    int count;
  910. X
  911. X    if( !depth ) return;
  912. X
  913. X    basep=filename+strlen(filename);
  914. X    dirp=fopen(filename,"r");
  915. X    if( dirp == NULL ) return;
  916. X    for(count = fread(&dp,sizeof(struct direct),1,dirp); count;
  917. X        count = fread(&dp,sizeof(struct direct),1,dirp) ) {
  918. X
  919. X        if( dp.d_name[0]=='.' && dp.d_name[1]=='\0' ) continue;
  920. X        if( dp.d_name[0]=='.' && dp.d_name[1]=='.' &&
  921. X            dp.d_name[2]=='\0' ) continue;
  922. X        strcpy(basep,dp.d_name);
  923. X        if( lstat(filename,&statbuf) < 0 ) continue;
  924. X        (*func)(filename,&statbuf);
  925. X        if( isproper( statbuf.st_mode ) ) {
  926. X            basep[ strlen(dp.d_name) ] = '/';
  927. X            basep[ strlen(dp.d_name)+1 ] = '\0';
  928. X            fwt1(depth-1);
  929. X        }
  930. X    }
  931. X    fclose(dirp);
  932. X    *basep = '\0';
  933. X}
  934. X
  935. X#endif
  936. END_OF_FILE
  937. if test 5549 -ne `wc -c <'rhdir.c'`; then
  938.     echo shar: \"'rhdir.c'\" unpacked with wrong size!
  939. fi
  940. # end of 'rhdir.c'
  941. fi
  942. if test -f 'rhparse.c' -a "${1}" != "-c" ; then 
  943.   echo shar: Will not clobber existing file \"'rhparse.c'\"
  944. else
  945. echo shar: Extracting \"'rhparse.c'\" \(10196 characters\)
  946. sed "s/^X//" >'rhparse.c' <<'END_OF_FILE'
  947. X
  948. X/* ----------------------------------------------------------------------
  949. X * FILE: rhparse.c
  950. X * (c) 1989 Ken Stauffer
  951. X * This contains the parser for the C expressions,
  952. X * gettoken(), getit() and ungetit() routines.
  953. X * sectime(), datespec(), expression(), expr(), exp0(), ... , factor()
  954. X * locatename(), push(), find_macro()
  955. X *
  956. X *
  957. X * ---------------------------------------------------------------------- */
  958. X
  959. X#include "rh.h"
  960. X#include <ctype.h>
  961. X#include <pwd.h>
  962. X
  963. Xstatic int cpos;        /* current character position */
  964. X
  965. X/* ----------------------------------------------------------------------
  966. X * getit:
  967. X *    Return the next character, input of from a file or
  968. X *    a string.
  969. X */
  970. X
  971. Xgetit()
  972. X{
  973. X    cpos++;
  974. X    if( dashe ) return( (*expstr) ? *expstr++ : EOF );
  975. X    else return( getc(expfile) );
  976. X}
  977. X
  978. X/* ----------------------------------------------------------------------
  979. X * ungetit:
  980. X *    Unget a char.
  981. X *
  982. X */
  983. X
  984. Xungetit(c)
  985. Xint c;
  986. X{
  987. X    cpos--;
  988. X    if( dashe ) expstr = (*expstr) ? expstr-1 : expstr;
  989. X    else ungetc(c,expfile);
  990. X}
  991. X
  992. X/* ----------------------------------------------------------------------
  993. X * error:
  994. X *    Print an error message an quit.
  995. X */
  996. Xerror(s)
  997. Xchar *s;
  998. X{
  999. X    if( dashf )
  1000. X        fprintf(stderr,"File: %s, ",expstr);
  1001. X    else if( dashe )
  1002. X        fprintf(stderr,"argv[%d], ",dashe);
  1003. X    else
  1004. X        fprintf(stderr,"File: stdin, ");
  1005. X
  1006. X    fprintf(stderr,"char: %d, %s\n",cpos,s);
  1007. X    exit(-1);
  1008. X}
  1009. X
  1010. X/* ----------------------------------------------------------------------
  1011. X * push:
  1012. X *    "assemble" the instruction into the StackProgram[] array.
  1013. X *
  1014. X */
  1015. X
  1016. Xpush(t,val)
  1017. Xlong t,val;
  1018. X{
  1019. X    if( PC >= LENGTH ) error("no more space for expression!"); 
  1020. X    StackProgram[PC].i_type=t;
  1021. X    StackProgram[PC++].i_value=val;
  1022. X    return(PC-1);
  1023. X}
  1024. X
  1025. X/* ----------------------------------------------------------------------
  1026. X * find_macro:
  1027. X *    Routine consumes the input file until it reaches the
  1028. X *    macro name followed by a colon. If EOF
  1029. X *    is encountered first then the program quits.
  1030. X *
  1031. X */
  1032. X
  1033. Xfind_macro()
  1034. X{
  1035. X    while( token != MACRONAME && token != EOF ) token = gettoken();
  1036. X    if( token == EOF ) error("macro name not found");
  1037. X    token = gettoken();
  1038. X    if( token != COLON ) error("missing ':' after macro name");
  1039. X    token = gettoken();
  1040. X}
  1041. X
  1042. X/* ----------------------------------------------------------------------
  1043. X * expression()
  1044. X *    Parse an expression.
  1045. X *    This routine calls exp() and exp() calls exp0() and so on...
  1046. X *    If the -m option was specified then the routine find_macro()
  1047. X *    is called.
  1048. X *    The NOW constant is initialized here.
  1049. X *
  1050. X */
  1051. X    
  1052. Xexpression()
  1053. X{
  1054. X    PC = 0; cpos = 0;
  1055. X    constants[ NOW_INDEX ] = time(0);
  1056. X    token = gettoken();
  1057. X    if( dashm ) find_macro();
  1058. X    expr();
  1059. X    if( token!= ';' && token!= EOF ) error("missing ';' or EOF");
  1060. X    push(0,0);            /* NULL terminated the program */
  1061. X}
  1062. X
  1063. X/* OPERATOR ?: */
  1064. Xexpr()
  1065. X{
  1066. X    int qm,colon,nop;
  1067. X
  1068. X    expr0();
  1069. X    if( token == QM ) {
  1070. X        token = gettoken();
  1071. X        qm = push(QM,0);
  1072. X        expr();
  1073. X        if( token != COLON ) error("missing ':'");
  1074. X        token = gettoken();
  1075. X        colon = push(COLON,0);
  1076. X        expr();
  1077. X        nop = push(NOP,0);        /* nop */
  1078. X
  1079. X        StackProgram[qm].i_value = colon;
  1080. X        StackProgram[colon].i_value = nop;
  1081. X    }
  1082. X}        
  1083. X
  1084. X/* OPERATOR || */ 
  1085. Xexpr0()
  1086. X{
  1087. X    expr1();
  1088. X    for(;;)
  1089. X        if( token == OR ) {
  1090. X            token = gettoken();
  1091. X            expr1();
  1092. X            push(OR,0);
  1093. X           } else break;
  1094. X}
  1095. X
  1096. X/* OPERATOR && */ 
  1097. Xexpr1()
  1098. X{
  1099. X    expr2();
  1100. X    for(;;)
  1101. X        if( token == AND ) {
  1102. X            token = gettoken();
  1103. X            expr2();
  1104. X            push(AND,0);
  1105. X        } else break;
  1106. X}
  1107. X
  1108. X/* OPERATOR | */
  1109. Xexpr2()
  1110. X{
  1111. X    expr3();
  1112. X    for(;;)
  1113. X        if( token == BOR ) {
  1114. X            token = gettoken();
  1115. X            expr3();
  1116. X            push(BOR,0);
  1117. X        } else break;
  1118. X}
  1119. X
  1120. X/* OPERATOR ^ */
  1121. Xexpr3()
  1122. X{
  1123. X    expr4();
  1124. X    for(;;)
  1125. X        if( token == BXOR ) {
  1126. X            token = gettoken();
  1127. X            expr4();
  1128. X            push(BXOR,0);
  1129. X        } else break;
  1130. X}
  1131. X
  1132. X/* OPERATOR & */
  1133. Xexpr4()
  1134. X{
  1135. X    expr5();
  1136. X    for(;;)
  1137. X        if( token == BAND ) {
  1138. X            token = gettoken();
  1139. X            expr5();
  1140. X            push(BAND,0);
  1141. X        } else break;
  1142. X}
  1143. X
  1144. X/* OPERATOR == != */
  1145. Xexpr5()
  1146. X{
  1147. X    int t;
  1148. X    expr6();
  1149. X    for(;t=token;)
  1150. X        if( t==EQ || t==NE ) {
  1151. X            token = gettoken();
  1152. X            expr6();
  1153. X            push(t,0);
  1154. X        } else break;
  1155. X}
  1156. X
  1157. X/* OPERATOR < <= > >= */
  1158. Xexpr6()
  1159. X{
  1160. X    int t;
  1161. X    expr7();
  1162. X    for(;t=token;)
  1163. X        if( t==LE || t==GE || t==GT || t==LT ) {
  1164. X            token = gettoken();
  1165. X            expr7();
  1166. X            push(t,0);
  1167. X        } else break;
  1168. X}
  1169. X
  1170. X/* OPERATOR << >> */
  1171. Xexpr7()
  1172. X{
  1173. X    int t;
  1174. X    expr8();
  1175. X    for(;t=token;)
  1176. X        if( t==SHIFTL || t==SHIFTR ) {
  1177. X            token = gettoken();
  1178. X            expr8();
  1179. X            push(t,0);
  1180. X        } else break;
  1181. X}
  1182. X
  1183. X/* OPERATOR + - */
  1184. Xexpr8()
  1185. X{
  1186. X    int t;
  1187. X    expr9();
  1188. X    for(;t=token;)
  1189. X        if( t==PLUS || t==MINUS ) {
  1190. X            token = gettoken();
  1191. X            expr9();
  1192. X            push(t,0);
  1193. X        } else break;
  1194. X}
  1195. X
  1196. X/* OPERATOR * / % */
  1197. Xexpr9()
  1198. X{
  1199. X    int t;
  1200. X    expr10();
  1201. X    for(;t=token;)
  1202. X        if( t==MUL || t==DIV || t==MOD ) {
  1203. X            token = gettoken();
  1204. X            expr10();
  1205. X            push(t,0);
  1206. X        } else break;
  1207. X}
  1208. X
  1209. X/* OPERATOR ~ ! - */ 
  1210. Xexpr10()
  1211. X{
  1212. X    int t;
  1213. X    t = token;    
  1214. X    if( t==NOT || t==BNOT || t==MINUS ){
  1215. X        token = gettoken();
  1216. X        expr10();
  1217. X        push((t==MINUS)? UNIMINUS : t ,0);
  1218. X    } else factor();
  1219. X}
  1220. X
  1221. X/* ----------------------------------------------------------------------
  1222. X * factor:
  1223. X *    Parse a factor. Could be a number, variable or
  1224. X *    string.
  1225. X */
  1226. Xfactor()
  1227. X{
  1228. X    long l,datespec();
  1229. X
  1230. X    switch(token) {
  1231. X        case '(':
  1232. X            token = gettoken();
  1233. X            expr();
  1234. X            if( token != ')' )
  1235. X                error("missing ')'");
  1236. X            token = gettoken();
  1237. X            break;
  1238. X        case NUMBER:
  1239. X            push(NUMBER,tokenval);
  1240. X            token = gettoken();
  1241. X            break;
  1242. X        case FIELD:
  1243. X            push(FIELD,tokenval);
  1244. X            token = gettoken();
  1245. X            break;
  1246. X        case '[':
  1247. X            token = gettoken();
  1248. X            l=datespec();
  1249. X            if( token != ']' )
  1250. X                error("missing ']'");
  1251. X            token = gettoken();
  1252. X            push(NUMBER,l);
  1253. X            break;
  1254. X        case STAR:
  1255. X            push(STAR,tokenval);
  1256. X            token = gettoken();
  1257. X            break;
  1258. X        default:
  1259. X            error("syntax error");
  1260. X    }
  1261. X}
  1262. X
  1263. X/* ----------------------------------------------------------------------
  1264. X * sectime:
  1265. X *    calculate the number of seconds between January 1, 1970
  1266. X *    and year/month/day. Return that value.
  1267. X *
  1268. X */
  1269. X
  1270. X#define leap(d)    (((d % 4 == 0) && (d % 100 != 0)) || (d % 400 == 0))
  1271. X#define DAYSEC    (3600*24)
  1272. X#define YERSEC    (3600*24*365)
  1273. X#define TIME0    1970
  1274. X
  1275. Xlong sectime(year,month,day)
  1276. Xint year,month,day;
  1277. X{
  1278. X
  1279. X        static int months[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
  1280. X    int yeardays,leapers,x;
  1281. X    long seconds;
  1282. X
  1283. X    if(month>12 || month<1 || year<TIME0 || day<1 || day>months[month]+
  1284. X        (month==2 && leap(year)) )
  1285. X            return(-1);
  1286. X
  1287. X    yeardays = leapers = 0;
  1288. X
  1289. X    for(x=1;x<month;x++)
  1290. X        yeardays += months[x];
  1291. X    if ((month > 2) && leap(year)) yeardays++;
  1292. X
  1293. X    for(x=TIME0; x<year; x++)
  1294. X        if(leap(x)) leapers++;
  1295. X    
  1296. X    seconds = yeardays*DAYSEC+(year-TIME0)*YERSEC+7*3600+
  1297. X            leapers*DAYSEC + day*DAYSEC;
  1298. X
  1299. X    return(seconds);
  1300. X
  1301. X}
  1302. X
  1303. X/* ----------------------------------------------------------------------
  1304. X * datespec:
  1305. X *    parse a date. Return the number of seconds from
  1306. X *    some date in 1970, until the specified date.
  1307. X */
  1308. X
  1309. Xlong datespec()
  1310. X{
  1311. X    int year,month,day,seconds;
  1312. X
  1313. X    if( token != NUMBER ) error("number expected");
  1314. X    year = tokenval;
  1315. X    token = gettoken();
  1316. X    if( token != DIV ) error("missing '/'");
  1317. X    token = gettoken();
  1318. X    if( token != NUMBER ) error("number expected");
  1319. X    month = tokenval;
  1320. X    token = gettoken();
  1321. X    if( token != DIV ) error("missing '/'");
  1322. X    token = gettoken();
  1323. X    if( token != NUMBER ) error("number expected");
  1324. X    day = tokenval;
  1325. X    token = gettoken();
  1326. X
  1327. X    if( (seconds = sectime(year,month,day)) < 0 ) 
  1328. X        error("invalid date");
  1329. X
  1330. X    return(seconds);
  1331. X}
  1332. X
  1333. X
  1334. X/* ----------------------------------------------------------------------
  1335. X * locatename:
  1336. X *    Does a linear seach for 's' in the array 'identifiers[]'.
  1337. X *
  1338. X */
  1339. X
  1340. Xlocatename(s)
  1341. Xchar *s;
  1342. X{
  1343. X    register int i;
  1344. X
  1345. X    for(i=0; identifiers[i]; i++ )
  1346. X        if( !strcmp(s,identifiers[i]) ) return(i);
  1347. X    return(-1);
  1348. X}
  1349. X
  1350. X/* ----------------------------------------------------------------------
  1351. X * gettoken:
  1352. X *    Return the next token.
  1353. X *    global variable: tokenval will contain any extra
  1354. X *    attribute associated with the returned token, ie
  1355. X *    the VALUE of a number, the index of the string etc...
  1356. X *
  1357. X */
  1358. Xgettoken()
  1359. X{
  1360. X    char buf[IDLENGTH+1],*bufp=buf;
  1361. X    int c;
  1362. X
  1363. X    for(;;) { 
  1364. X        while( (c=getit()) == ' ' || c=='\n' || c=='\t' );
  1365. X        if( c == '#' ) while( (c=getit())!= '\n' && c!= EOF );
  1366. X        else break;
  1367. X    }
  1368. X
  1369. X    if(c=='0') {
  1370. X        tokenval=0;
  1371. X        while( ( c=getit() ) >= '0' && c <= '7' ) {
  1372. X            tokenval <<= 3;
  1373. X            tokenval += c-'0';
  1374. X        }
  1375. X        if( isdigit(c) ) error("bad octal constant");
  1376. X        ungetit(c);
  1377. X        return(NUMBER);
  1378. X    }
  1379. X    if(isdigit(c)) {
  1380. X        tokenval=c-'0';
  1381. X        while(isdigit( (c=getit()) )) {
  1382. X            tokenval *=10;
  1383. X            tokenval += c-'0';
  1384. X        }
  1385. X        ungetit(c);
  1386. X        return(NUMBER);
  1387. X    }
  1388. X    
  1389. X    if(isalpha(c)) {
  1390. X       int count=0,index;
  1391. X       do {
  1392. X        if(count++ < IDLENGTH) *bufp++ = c;
  1393. X        c=getit();
  1394. X       } while( isalnum(c) );
  1395. X       ungetit(c);
  1396. X       *bufp='\0';
  1397. X       if( (index=locatename(buf)) < 0 ) return(UNKNOWN);
  1398. X       tokenval = constants[index];
  1399. X       if( index==MACRO_INDEX ) return(MACRONAME);
  1400. X       return( ( isupper( *(identifiers[index]) ) ? NUMBER : FIELD ) );
  1401. X    }
  1402. X
  1403. X    if( c == '"' ) {
  1404. X        int index,st=0;
  1405. X        index=starfree;
  1406. X        while( (c=getit())!= '"' ) {
  1407. X            if( starfree > STARLEN )
  1408. X                error("no more string space");
  1409. X            if(c=='*') st++;
  1410. X            if(st>1) error("too many *'s present");
  1411. X            Starbuf[starfree++]=c;
  1412. X        }
  1413. X        Starbuf[starfree++]='\0';
  1414. X        tokenval=index;
  1415. X        return(STAR);
  1416. X    }
  1417. X
  1418. X    if( c == '=' ) {
  1419. X        c=getit();
  1420. X        if(c== '=') return(EQ);
  1421. X        else {
  1422. X            ungetit(c);
  1423. X            return('=');
  1424. X        }
  1425. X    }
  1426. X
  1427. X    if( c== '$' ) {
  1428. X       int count=0;
  1429. X       struct passwd *info,*getpwnam();
  1430. X       c=getit();
  1431. X       do {
  1432. X        if (count++ < IDLENGTH) *bufp++ = c;
  1433. X        c=getit();
  1434. X       } while( isalnum(c) );
  1435. X       ungetit(c);
  1436. X       *bufp='\0';
  1437. X       info=getpwnam(buf);
  1438. X       if(info == NULL)
  1439. X        error("unknown user name after $");
  1440. X       tokenval = info->pw_uid;
  1441. X       return( NUMBER );
  1442. X    }
  1443. X    
  1444. X    if( c == '!' ) {
  1445. X        c=getit();
  1446. X        if( c == '=' ) return(NE);
  1447. X        ungetit(c);
  1448. X        return(NOT);
  1449. X    }
  1450. X    if( c == '>' ) {
  1451. X        c=getit();
  1452. X        if( c == '=' ) return(GE);
  1453. X        if( c == '>' ) return(SHIFTR);
  1454. X        ungetit(c);
  1455. X        return(GT);
  1456. X    }
  1457. X
  1458. X    if( c == '<' ) {
  1459. X        c=getit();
  1460. X        if( c == '=' ) return(LE);
  1461. X        if( c == '<' ) return(SHIFTL);
  1462. X        ungetit(c);
  1463. X        return(LT);
  1464. X    }
  1465. X
  1466. X    if( c == '&' ) {
  1467. X        c=getit();
  1468. X        if( c == '&' ) return(AND);
  1469. X        ungetit(c);
  1470. X        return(BAND);
  1471. X    }
  1472. X
  1473. X    if( c == '|' ) {
  1474. X        c=getit();
  1475. X        if( c == '|' ) return(OR);
  1476. X        ungetit(c);
  1477. X        return(BOR);
  1478. X    }
  1479. X    if( c == '^' ) return(BXOR);
  1480. X    if( c == '+' ) return(PLUS);
  1481. X    if( c == '-' ) return(MINUS);
  1482. X    if( c == '*' ) return(MUL);
  1483. X    if( c == '/' ) return(DIV);
  1484. X    if( c == '%' ) return(MOD);
  1485. X    if( c == '~' ) return(BNOT);
  1486. X    if( c == '?' ) return(QM);
  1487. X    if( c == ':' ) return(COLON);
  1488. X    
  1489. X    return(c);
  1490. X}
  1491. X
  1492. END_OF_FILE
  1493. if test 10196 -ne `wc -c <'rhparse.c'`; then
  1494.     echo shar: \"'rhparse.c'\" unpacked with wrong size!
  1495. fi
  1496. # end of 'rhparse.c'
  1497. fi
  1498. if test -f 'rh.man' -a "${1}" != "-c" ; then 
  1499.   echo shar: Will not clobber existing file \"'rh.man'\"
  1500. else
  1501. echo shar: Extracting \"'rh.man'\" \(6020 characters\)
  1502. sed "s/^X//" >'rh.man' <<'END_OF_FILE'
  1503. X.TH RH 1
  1504. X.SH NAME
  1505. Xrh - recursive file locater (rawhide)
  1506. X.SH SYNOPSIS
  1507. X.BI "rh [-rlha] [-f" " filename" " [-m" "name" "] | -e" " expression"
  1508. X.BI "] [" "file" " ...]"
  1509. X.SH DECRIPTION
  1510. X.I Rh
  1511. Xrecursively searches the file system starting at
  1512. X.I file ...
  1513. Xfor files that make a C expression true. If no
  1514. X.I files
  1515. Xare listed then the current working directory is used.
  1516. X.PP
  1517. XExpressions for
  1518. X.I rh
  1519. Xcan come from the command line, a file, or from
  1520. Xstandard input (if no
  1521. X.I -e
  1522. Xor
  1523. X.I -f
  1524. Xoptions are given).
  1525. XThe basic form of a
  1526. X.I rh
  1527. Xexpression consists of a valid C expression containing
  1528. Xinteger constants and variables.
  1529. X.PP
  1530. X.I Constants
  1531. X, are either numeric or symbolic. Symbolic constants refer
  1532. Xto the #define's in the file
  1533. X.I /usr/include/sys/stat.h.
  1534. XOnly the useful constants are implemented. All symbolic
  1535. Xconstants are UPPER CASE and the "S_" prefix from the
  1536. Xsymbol name is omitted.
  1537. X.PP
  1538. X.I Variables
  1539. X, are lower case symbols that specify a field in the
  1540. Xstat structure (eg. st_size,st_mode ). For each file examined by
  1541. X.I rh
  1542. Xthese internal varibles are updated to match the current
  1543. Xfile. For convienience the "st_" prefix is dropped from variable
  1544. Xnames.
  1545. X.SH OPTIONS
  1546. X.B Rh
  1547. Xoptions can appear in any order, multiple options can
  1548. Xbe together within the same argument. However
  1549. Xno options may occur
  1550. X.I after
  1551. Xthe filename list is given.
  1552. X.IP -r
  1553. XThis option
  1554. X.B disables
  1555. X.I rh
  1556. Xfrom recursively searching for files.
  1557. X.PP
  1558. X.IP -l
  1559. XNormally
  1560. X.I rh
  1561. Xprints each matching filename on a line by itself. However,
  1562. X.I -l
  1563. Xwill cause filenames to be displayed with permission modes and
  1564. Xthe file size. Filename printing is similar to that of the
  1565. X.I ls
  1566. X(1) command. 
  1567. X.PP
  1568. X.IP -h
  1569. XThis tells
  1570. X.I rh
  1571. Xto display a useful help message. The message
  1572. Xexplains the command line usage, a list of
  1573. Xavailable constants/variables and a list
  1574. Xof valid operators.
  1575. X.I Rh
  1576. Xthen continues as though the
  1577. X.I -h
  1578. Xoption was not present.
  1579. X.PP
  1580. X.IP -f
  1581. XExpects that the next argument will be the
  1582. X.I filename
  1583. Xof a file containing a
  1584. X.I rh
  1585. Xexpression. It is an error to have both the
  1586. X.I -f
  1587. Xand
  1588. X.I -e
  1589. Xoptions together. Expressions should appear
  1590. Xin
  1591. X.I filename
  1592. Xin the same manner as expressions that are
  1593. Xentered interactively. The
  1594. X.I -m
  1595. Xoption expands this to allow labels to appear in the file.
  1596. XSee
  1597. X.I -m
  1598. Xfor more details.
  1599. X.PP
  1600. X.IP -m
  1601. XIs followed immediatly by a
  1602. X.I macroname
  1603. Xwhich specifies the starting location of a
  1604. X.I rh
  1605. Xexpression within the file
  1606. X.I filename.
  1607. XA ':' must appear after
  1608. X.I macroname.
  1609. XFor example:
  1610. X.PP
  1611. X.RS 8
  1612. Xwritable:
  1613. X.RS 5
  1614. X(mode & 022) && (uid == $joe );
  1615. X.PP
  1616. X.RE
  1617. X.RE
  1618. X.IP
  1619. XA
  1620. X.I -mwritable
  1621. Xoption would cause the expression following
  1622. X.I writeable:
  1623. Xto be used as the
  1624. X.I rh
  1625. Xexpression.
  1626. X.PP
  1627. X.IP -e
  1628. XThis option takes the next argument as the
  1629. X.I rh
  1630. X.I expression
  1631. Xthat will be used for the file search. Since many
  1632. Xof the operators are also
  1633. X.I sh
  1634. X(1) meta characters and since expressions may have
  1635. Xspaces in them, it is strongly recommended that the
  1636. X.I expression
  1637. Xbe enclosed in ''.
  1638. X.PP
  1639. X.IP -a
  1640. XThis option
  1641. X.I adds
  1642. Xmore information to the long output of the
  1643. X.I -l
  1644. Xoption. Information such as uid, gid, and last modified date
  1645. Xare output. The
  1646. X.I -a
  1647. Xoption implies the
  1648. X.I -l
  1649. Xoption.
  1650. X.PP
  1651. X.SH USAGE
  1652. X.SS "The following are the valid constants:"
  1653. X.IP NOW
  1654. XThis constant is set to the current time at the start of
  1655. X.I rh.
  1656. XIt is used to make comparisons with atime,ctime and mtime.
  1657. X.PP
  1658. X.I
  1659. XIFBLK IFDIR IFLNK IFMT IFREG IFSOCK ISGID ISUID ISVTX -
  1660. Xsee stat(2).
  1661. X.PP
  1662. X.SS "The following are the valid variables:"
  1663. X.PP
  1664. X.I
  1665. Xatime ctime dev gid ino mode mtime nlink rdev size uid -
  1666. Xsee stat(2).
  1667. X.PP
  1668. X.SS "Valid C operators are:"
  1669. X.PP
  1670. X! ~ - * / % + < <= > >= == != & ^ | << >> && || ?:
  1671. X.PP
  1672. XOperator precedence, associativity and semantics are idenitical
  1673. Xto C.
  1674. X.PP
  1675. X.SS "Special operators:"
  1676. X.PP
  1677. X.IP $username
  1678. XThis operater evaluates to the integer uid of
  1679. X.I username.
  1680. X.PP
  1681. X.IP """*.c"""
  1682. XThis operator evaluates to true if the current filename matches
  1683. X"expression". The only form of 
  1684. X.I expression
  1685. Xsupported is, "filename", "*filename", "filename*", "*".
  1686. XWhen doing comparisons, only the base name is examined, not
  1687. Xpathnames.
  1688. X.PP
  1689. X.IP [yyyy/mm/dd]
  1690. XThe date enclosed in the [], will evaluate to a numeric
  1691. Xquantity suitable for comparing with atime,mtime or ctime.
  1692. XThe year cannot be abbreviated to say, 89 for 1989.
  1693. X.PP
  1694. X.IP NOTE:
  1695. XThat the
  1696. X.I special operators
  1697. Xtake on higher precedence than the C operators.
  1698. X.PP
  1699. X.SS "Lexical conventions:"
  1700. X.PP
  1701. XNumbers may be entered in octal by preceeding it with
  1702. Xa leading zero. Otherwise the number is taken to be
  1703. Xdecimal.
  1704. X.PP
  1705. X.PP
  1706. XAll characters after a '#' symbol are ignored upto a
  1707. Xnewline or end of file. This allows for comments
  1708. Xin rh expression files.
  1709. X.PP
  1710. XAn expression may be terminated by either
  1711. Xa ';' or EOF.
  1712. X.PP
  1713. X.SH EXAMPLES
  1714. XThe following are examples of
  1715. X.I rh
  1716. Xexpression. All expressions may appear in either a file,
  1717. Xinteractively, or on the command line:
  1718. X.PP
  1719. X.RS 8
  1720. X(mode & 022) && (uid == $joe );
  1721. X.PP
  1722. X.RE
  1723. XMatches all files that have uid equal to username 'joe' and
  1724. Xis writable by other people.
  1725. X.PP
  1726. X.RS 8
  1727. X!uid && (mode & ISUID ) && (mode & 02);
  1728. X.PP
  1729. X.RE
  1730. XMatches all files that are owned by root (uid==0) and that
  1731. Xhave set-uid on execution bit set, and is writable.
  1732. X.PP
  1733. X.RS 8
  1734. X(size > 10*1024) && (mode & 0111) && (atime <= NOW-24*3600);
  1735. X.PP
  1736. X.RE
  1737. XThis expression finds all executable files greater than 10K, that
  1738. Xhave not been executed in the last 24 hours.
  1739. X.PP
  1740. X.RS 8
  1741. Xsize < ( ("*.c") ? 4096 : 32*1024 );
  1742. X.PP
  1743. X.RE
  1744. XThis cryptic expression finds C source files less than 4K, or
  1745. Xwill find other files if they are smaller than 32K. No other files
  1746. Xwill match.
  1747. X.PP
  1748. X.RS 8
  1749. X!(size % 1024);
  1750. X.PP
  1751. X.RE
  1752. XMatches files that are a multiple of 1K.
  1753. X.PP
  1754. X.RS 8
  1755. Xmtime >= [1982/3/1] && mtime <= [1982/3/31];
  1756. X.PP
  1757. X.RE
  1758. XThis exression finds files that were modified during the
  1759. Xmonth of march, in the year 1982.
  1760. X.PP
  1761. X.SH SEE ALSO
  1762. Xsh(1), find(1), stat(2), ls(1), chmod(1)
  1763. X.PP
  1764. XThe C programming language.
  1765. X.SH AUTHOR
  1766. XKen Stauffer (University of Calgary)
  1767. X.PP
  1768. Xstauffer@sixk
  1769. X.PP
  1770. X.SH BUGS
  1771. XThe date operator should also allow for time to be entered.
  1772. XFull regular exressions should be allowed within the " " operator.
  1773. X.PP
  1774. END_OF_FILE
  1775. if test 6020 -ne `wc -c <'rh.man'`; then
  1776.     echo shar: \"'rh.man'\" unpacked with wrong size!
  1777. fi
  1778. # end of 'rh.man'
  1779. fi
  1780. if test -f 'sample' -a "${1}" != "-c" ; then 
  1781.   echo shar: Will not clobber existing file \"'sample'\"
  1782. else
  1783. echo shar: Extracting \"'sample'\" \(553 characters\)
  1784. sed "s/^X//" >'sample' <<'END_OF_FILE'
  1785. X# This file contains 'rh' expressions.
  1786. X# '#' character causes the rest of the line to
  1787. X# be ignored...
  1788. X#
  1789. X
  1790. X# ex1, ex2, ex3, ex4, ex5 come from the manual...
  1791. X#
  1792. Xex1:
  1793. X    (mode & 022) && (uid == $uucp );
  1794. X
  1795. Xex2:
  1796. X    !uid && (mode & ISUID ) && (mode & 02);
  1797. X
  1798. Xex3:
  1799. X    (size > 10*1024) && (mode & 0111) && (atime <= NOW-24*3600);
  1800. X
  1801. Xex4:
  1802. X    size < (("*.c") ? 4096 : 32*1024);
  1803. X
  1804. Xex5:
  1805. X    !(size % 1024);
  1806. X
  1807. X# find files that have been created in the last hour.
  1808. X#
  1809. Xnew:
  1810. X    ctime > NOW-3600;
  1811. X
  1812. X# find files who have not been modified in the last 30 days.
  1813. X#
  1814. Xaged:
  1815. X    mtime < NOW-30*24*3600;
  1816. X
  1817. END_OF_FILE
  1818. if test 553 -ne `wc -c <'sample'`; then
  1819.     echo shar: \"'sample'\" unpacked with wrong size!
  1820. fi
  1821. # end of 'sample'
  1822. fi
  1823. echo shar: End of shell archive.
  1824. exit 0
  1825.  
  1826.